package cn.zyq.ykb.controller.file;


import cn.zyq.ykb.beans.file.FileStorage;
import cn.zyq.ykb.beans.file.StsToken;
import cn.zyq.ykb.service.file.FileStorageService;
import cn.zyq.ykb.system.common.BackParam;
import cn.zyq.ykb.system.common.BaseController;
import cn.zyq.ykb.system.cos.AliyunCos;
import cn.zyq.ykb.system.cos.CosService;
import cn.zyq.ykb.system.enums.core.ResponseCodeEnum;
import cn.zyq.ykb.system.utils.FileInfo;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.*;
import com.aliyun.oss.model.*;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.auth.sts.AssumeRoleRequest;
import com.aliyuncs.auth.sts.AssumeRoleResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;

import com.aliyuncs.exceptions.ClientException;

/**
 * @Description: 公共接口类
 * @Author pengdoudou
 * @Date 2023/4/20 14:43
 */
@Slf4j
@Api(tags = "文件接口类")
@RestController(value = "fileCommonController")
@RequestMapping(value = "/file/")
public class FileController extends BaseController {
    @Autowired
    private CosService cosService;

    @Autowired
    private FileStorageService fileStorageService;

    /**
     * 上传文件
     *
     * @param file
     * @return
     * @throws IOException
     */
    @ApiOperation(value = "上传文件", response = FileInfo.class)
    @PostMapping("/upload")
    public Object upload(@RequestParam("file") MultipartFile file) throws IOException {
        log.info("【请求开始】上传文件,请求参数,file:{}", file.getOriginalFilename());
        String originalFilename = file.getOriginalFilename();
        FileStorage storage = cosService.store(file.getInputStream(), file.getSize(), file.getContentType(),
                originalFilename);
        log.info("【请求结束】上传文件,响应结果:{}", JSONObject.toJSONString(storage));
        BackParam backParam = new BackParam();
        backParam.setMsg(ResponseCodeEnum.SUCCESS.getMsg());
        backParam.setCode(ResponseCodeEnum.SUCCESS.getCode());
        backParam.setData(storage);
        return backParam;
    }

    /**
     * 访问存储对象
     *
     * @param key 存储对象key
     * @return
     */
    @ApiOperation(value = "访问文件")
    @GetMapping("/{key:.+}")
    public ResponseEntity<Resource> fetch(@PathVariable String key) {
        log.info("【请求开始】访问本地存储对象,请求参数,key:{}", key);
        FileStorage Storage = fileStorageService.findByKey(key);
        if (key == null) {
            return ResponseEntity.notFound().build();
        }
        if (key.contains("../")) {
            return ResponseEntity.badRequest().build();
        }
        String type = Storage.getType();
        MediaType mediaType = MediaType.parseMediaType(type);
        Resource file = cosService.loadAsResource(key);
        if (file == null) {
            return ResponseEntity.notFound().build();
        }
        if (type.equals("application/vnd.android.package-archive")
                || type.equals("application/octet-stream")) {
            //处理apk下载变为txt
            if (mediaType.isCompatibleWith(MediaType.TEXT_PLAIN)) {
                if (type.equals("application/vnd.android.package-archive")) {
                    mediaType = MediaType.parseMediaType("application/vnd.android.package-archive");
                }
                if (type.equals("application/octet-stream")) {
                    mediaType = MediaType.parseMediaType("application/octet-stream");
                }
            }
            log.info("【请求结束】访问存储对象,响应结果:{},{}", "成功", file);
            return ResponseEntity.ok()
                    .contentType(mediaType)
                    .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + key + "\"")
                    .body(file);
        }
        log.info("【请求结束】访问存储对象,响应结果:{},{}", "成功", file);
        return ResponseEntity.ok().contentType(mediaType).body(file);
    }


    @Autowired
    private AliyunCos aliyunCos;
//
//    @ApiOperation(value = "上传文件", response = FileInfo.class)
//    @PostMapping("/uploadVideo")
//    public Object uploadVideo(@RequestParam("file") MultipartFile file, @RequestParam("filePath") String filePath) throws Exception {
//        // Endpoint以华东1（杭州）为例，其它Region请按实际情况填写。
//        String endpoint = aliyunCos.getEndpoint();
//        String accessKeyId = aliyunCos.getAccessKeyId();
//        String accessKeySecret = aliyunCos.getAccessKeySecret();
//        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
//        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
//        // 填写Bucket名称，例如examplebucket。
//        String bucketName = aliyunCos.getBucketName();
//        // 填写Object完整路径，例如exampledir/exampleobject.txt。Object完整路径中不能包含Bucket名称。
////        String originalFilename = "examplebucket" ;
//        String originalFilename = file.getOriginalFilename();
//        log.info("==============="+originalFilename);
//        String key = cosService.upt(originalFilename);
//        log.info("==============="+key);
//        String objectName = key;
//
//        // 待上传本地文件路径。
////        String filePath = "E:\\f4b83b7a61d9f67062d34735f6c7bc9b.mp4";
//
//        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
//        conf.setSupportCname(true);
//
//        // 创建OSSClient实例。
//        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret, conf);
//        try {
//            // 创建InitiateMultipartUploadRequest对象。
//            InitiateMultipartUploadRequest request = new InitiateMultipartUploadRequest(bucketName, objectName);
//            // 如果需要在初始化分片时设置请求头，请参考以下示例代码。
//            ObjectMetadata metadata = new ObjectMetadata();
//            // 根据文件自动设置ContentType。如果不设置，ContentType默认值为application/oct-srream。
//            if (metadata.getContentType() == null) {
//                metadata.setContentType(Mimetypes.getInstance().getMimetype(new File(filePath), objectName));
//            }
//            // 初始化分片。
//            InitiateMultipartUploadResult upresult = ossClient.initiateMultipartUpload(request);
//            // 返回uploadId。
//            String uploadId = upresult.getUploadId();
//            // 根据uploadId执行取消分片上传事件或者列举已上传分片的操作。
//            // 如果您需要根据您需要uploadId执行取消分片上传事件的操作，您需要在调用InitiateMultipartUpload完成初始化分片之后获取uploadId。
//            // 如果您需要根据您需要uploadId执行列举已上传分片的操作，您需要在调用InitiateMultipartUpload完成初始化分片之后，且在调用CompleteMultipartUpload完成分片上传之前获取uploadId。
//            // System.out.println(uploadId);
//
//            // partETags是PartETag的集合。PartETag由分片的ETag和分片号组成。
//            List<PartETag> partETags = new ArrayList<PartETag>();
//            // 每个分片的大小，用于计算文件有多少个分片。单位为字节。
//            final long partSize = 1 * 1024 * 1024L;   //1 MB。
//
//            // 根据上传的数据大小计算分片数。以本地文件为例，说明如何通过File.length()获取上传数据的大小。
//            final File sampleFile = new File(filePath);
//            long fileLength = sampleFile.length();
//            int partCount = (int) (fileLength / partSize);
//            if (fileLength % partSize != 0) {
//                partCount++;
//            }
//            // 遍历分片上传。
//            for (int i = 0; i < partCount; i++) {
//                long startPos = i * partSize;
//                long curPartSize = (i + 1 == partCount) ? (fileLength - startPos) : partSize;
//                UploadPartRequest uploadPartRequest = new UploadPartRequest();
//                uploadPartRequest.setBucketName(bucketName);
//                uploadPartRequest.setKey(objectName);
//                uploadPartRequest.setUploadId(uploadId);
//                // 设置上传的分片流。
//                // 以本地文件为例说明如何创建FIleInputstream，并通过InputStream.skip()方法跳过指定数据。
//                InputStream instream = new FileInputStream(sampleFile);
//                instream.skip(startPos);
//                uploadPartRequest.setInputStream(instream);
//                // 设置分片大小。除了最后一个分片没有大小限制，其他的分片最小为100 KB。
//                uploadPartRequest.setPartSize(curPartSize);
//                // 设置分片号。每一个上传的分片都有一个分片号，取值范围是1~10000，如果超出此范围，OSS将返回InvalidArgument错误码。
//                uploadPartRequest.setPartNumber(i + 1);
//                // 每个分片不需要按顺序上传，甚至可以在不同客户端上传，OSS会按照分片号排序组成完整的文件。
//                UploadPartResult uploadPartResult = ossClient.uploadPart(uploadPartRequest);
//                // 每次上传分片之后，OSS的返回结果包含PartETag。PartETag将被保存在partETags中。
//                partETags.add(uploadPartResult.getPartETag());
//            }
//            // 创建CompleteMultipartUploadRequest对象。
//            // 在执行完成分片上传操作时，需要提供所有有效的partETags。OSS收到提交的partETags后，会逐一验证每个分片的有效性。当所有的数据分片验证通过后，OSS将把这些分片组合成一个完整的文件。
//            CompleteMultipartUploadRequest completeMultipartUploadRequest =
//                    new CompleteMultipartUploadRequest(bucketName, objectName, uploadId, partETags);
//            // 完成分片上传。
//            CompleteMultipartUploadResult completeMultipartUploadResult = ossClient.completeMultipartUpload(completeMultipartUploadRequest);
//            System.out.println(completeMultipartUploadResult.getETag());
//            Date expiration = new Date(new Date().getTime() + 3600 * 1000);
//            GeneratePresignedUrlRequest urlRequest = new GeneratePresignedUrlRequest(bucketName, objectName, HttpMethod.GET);
//            urlRequest.setExpiration(expiration);
//            String url = ossClient.generatePresignedUrl(urlRequest).toString();
//
//            log.info("==============================" + url);
//            String substring = url.substring(0, url.indexOf("?"));
//
//            log.info("==============================" + substring);
//            return substring;
//
//        } catch (OSSException oe) {
//            System.out.println("Caught an OSSException, which means your request made it to OSS, "
//                    + "but was rejected with an error response for some reason.");
//            System.out.println("Error Message:" + oe.getErrorMessage());
//            System.out.println("Error Code:" + oe.getErrorCode());
//            System.out.println("Request ID:" + oe.getRequestId());
//            System.out.println("Host ID:" + oe.getHostId());
//        } catch (ClientException ce) {
//            System.out.println("Caught an ClientException, which means the client encountered "
//                    + "a serious internal problem while trying to communicate with OSS, "
//                    + "such as not being able to access the network.");
//            System.out.println("Error Message:" + ce.getMessage());
//        } finally {
//            if (ossClient != null) {
//                ossClient.shutdown();
//            }
//        }
//
//        return null;
//    }

    @ApiOperation(value = "系统文件在线预览接口 by tarzan")
    @GetMapping("/onlinePreview/{url}")
    public void onlinePreview(@PathVariable("url") String url, HttpServletResponse response) throws Exception {
        fileStorageService.onlinePreview(url, response);
    }

    @ApiOperation(value = "上传文件", response = FileInfo.class)
    @PostMapping("/uploadVideo")
    public Object uploadVideo(@RequestParam("file") MultipartFile file) throws Exception {
        String endpoint = aliyunCos.getEndpoint();
        String accessKey = aliyunCos.getAccessKeyId();
        String secretKey = aliyunCos.getAccessKeySecret();
//        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey);
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration();
        conf.setSupportCname(true);

        // 创建OSSClient实例。
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKey, secretKey, conf);

        PutObjectRequest putObjectRequest;
        String filename = file.getOriginalFilename();
        try {
            putObjectRequest = new PutObjectRequest(aliyunCos.getBucketName(), filename, file.getInputStream());
            // 上传文件并覆盖原文件
            ossClient.putObject(putObjectRequest);
//            String url =  + filename;
            return "上传成功";
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            // 关闭OSSClient。
            ossClient.shutdown();
        }
        return "上传失败";
    }

    /**
     * 获取阿里云图片上传 STStoken接口
     *
     * @return
     */
    @PostMapping("/companies/getStsToken")
    public StsToken getStsToken() {
        // STS接入地址，例如sts.cn-hangzhou.aliyuncs.com。
        String endpoint = "sts.cn-chengdu.aliyuncs.com";
        String accessKeyId = "LTAI5tJe46zRkzUQiSSXv8aU";
        String accessKeySecret = "pcfZ1KRVkA4cUhvodhHxmRtkCwEwUQ";
        String roleArn = "acs:ram::1765686819584670:role/ramosstest";
        String roleSessionName = "ytk";
        // 以下Policy用于限制仅允许使用临时访问凭证向目标存储空间examplebucket下的src目录上传文件。
        // 临时访问凭证最后获得的权限是步骤4设置的角色权限和该Policy设置权限的交集，即仅允许将文件上传至目标存储空间examplebucket下的src目录。
        // 如果policy为空，则用户将获得该角色下所有权限。
        String policy = "{\n" +
                "    \"Version\": \"1\", \n" +
                "    \"Statement\": [\n" +
                "        {\n" +
                "            \"Action\": [\n" +
                "                \"oss:PutObject\"\n" +
                "            ], \n" +
                "            \"Resource\": [\n" +
                "                \"acs:oss:*:*:ykb2019/*\" \n" +
                "            ], \n" +
                "            \"Effect\": \"Allow\"\n" +
                "        }\n" +
                "    ]\n" +
                "}";
        // 设置临时访问凭证的有效时间为3600秒。
        Long durationSeconds = 3600L;
        try {
            // regionId表示RAM的地域ID。以华东1（杭州）地域为例，regionID填写为cn-hangzhou。也可以保留默认值，默认值为空字符串（""）。
            String regionId = "cn-chengdu";
            // 添加endpoint。适用于Java SDK 3.12.0及以上版本。
            DefaultProfile.addEndpoint(regionId, "Sts", endpoint);
            // 添加endpoint。适用于Java SDK 3.12.0以下版本。
            // DefaultProfile.addEndpoint("",regionId, "Sts", endpoint);
            // 构造default profile。
            IClientProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, accessKeySecret);
            // 构造client。
            DefaultAcsClient client = new DefaultAcsClient(profile);
            final AssumeRoleRequest request = new AssumeRoleRequest();
            // 适用于Java SDK 3.12.0及以上版本。
            request.setSysMethod(MethodType.POST);
            // 适用于Java SDK 3.12.0以下版本。
            //request.setMethod(MethodType.POST);
            request.setRoleArn(roleArn);
            request.setRoleSessionName(roleSessionName);
            request.setPolicy(policy);
            request.setDurationSeconds(durationSeconds);
            final AssumeRoleResponse response = client.getAcsResponse(request);

            StsToken stsToken = new StsToken();
            stsToken.setAccessKeyId(response.getCredentials().getAccessKeyId());
            stsToken.setAccessKeySecret(response.getCredentials().getAccessKeySecret());
            stsToken.setStsToken( response.getCredentials().getSecurityToken());
            stsToken.setBucket(aliyunCos.getBucketName());
            stsToken.setRegion("oss-cn-chengdu");

            log.info("Expiration: " + response.getCredentials().getExpiration());
            log.info("Access Key Id: " + response.getCredentials().getAccessKeyId());
            log.info("Access Key Secret: " + response.getCredentials().getAccessKeySecret());
            log.info("Security Token: " + response.getCredentials().getSecurityToken());
            log.info("RequestId: " + response.getRequestId());
            return stsToken;
        } catch (ClientException e) {
            System.out.println("Failed：");
            System.out.println("Error code: " + e.getErrCode());
            System.out.println("Error message: " + e.getErrMsg());
            System.out.println("RequestId: " + e.getRequestId());
        }
        return null;
    }


}